package com.linkallcloud.core.activity;

import java.util.List;

import com.linkallcloud.core.dao.IFlowStepDao;
import com.linkallcloud.core.domain.FlowStep;
import com.linkallcloud.core.dto.ObjVo;
import com.linkallcloud.core.dto.Trace;
import com.linkallcloud.core.enums.Agree;
import com.linkallcloud.core.exception.BaseRuntimeException;
import com.linkallcloud.core.exception.Exceptions;
import com.linkallcloud.core.lang.Strings;
import com.linkallcloud.core.query.Query;
import com.linkallcloud.core.query.rule.Equal;
import com.linkallcloud.core.util.Utils;

public abstract class FlowStepActivity<T extends FlowStep, D extends IFlowStepDao<T>> extends BaseActivity<T, D>
        implements IFlowStepActivity<T> {

    @Override
    public List<T> findByObj(Trace t, Integer flowType, Long objId, String objUuid, String objType,
            String objPropType) {
        Utils.assertNotNull(objId, "参数objId不能为空");
        Utils.assertNotBlank(objUuid, "参数objUuid不能为空");
        Utils.assertNotBlank(objType, "参数objType不能为空");

        Query q = new Query();
        if (flowType != null) {
            q.addRule(new Equal("flowType", flowType));
        }
        q.addRule(new Equal("objId", objId));
        q.addRule(new Equal("objUuid", objUuid));
        q.addRule(new Equal("objType", objType));
        if (!Strings.isBlank(objPropType)) {
            q.addRule(new Equal("objPropType", objPropType));
        }
        return dao().find(t, q);
    }

    @Override
    public List<T> findByTwf(Trace t, Long twfInstId, String twfInstUuid) {
        Utils.assertNotNull(twfInstId, "参数twfInstId不能为空");
        Utils.assertNotBlank(twfInstUuid, "参数twfInstUuid不能为空");

        Query q = new Query();
        q.addRule(new Equal("twfId", twfInstId));
        q.addRule(new Equal("twfUuid", twfInstUuid));
        return dao().find(t, q);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean flow(Trace t, T flow) {
        checkFlow(t, flow);

        if (flow.isAutoCreateStartNode()) {
            T startNode = (T) flow.clone();
            startNode.setUuid(startNode.generateUuid());
            startNode.createComplete();
            dao().insert(t, startNode);
            doConcreteCompleteBusiness(t, Agree.Yes.getCode(), startNode);
        }

        if (flow.isNeedTwfFlow() && !Strings.isBlank(flow.getTwfDefineCode())) {
            ObjVo twf = startTwf(t, flow);
            Utils.assertNotNull(twf, "启动流程失败，请联系管理员。");

            try {
                flow.setTwfId(twf.getId());
                flow.setTwfUuid(twf.getUuid());
                flow.createStart();
                dao().insert(t, flow);
            } catch (Throwable e) {
                cancelTwf(t, twf.getId(), twf.getUuid());
                throw e;
            }
        } else {
            flow.complete();
            dao().insert(t, flow);
            doConcreteCompleteBusiness(t, Agree.Yes.getCode(), flow);
        }

        return true;
    }

    @Override
    public int progress(Trace t, Long twfInstId, String twfInstUuid, int progress) {
        return dao().progress(t, twfInstId, twfInstUuid, progress);
    }

    @Override
    public ObjVo startTwf(Trace t, FlowStep flow) {
        IActivity<?> bzActivity = bzActivity(flow);
        if (bzActivity != null) {
            return bzActivity.startTwf(t, flow);
        }
        throw new BaseRuntimeException(Exceptions.CODE_ERROR_PARAMETER, "bzActivity未配置。");
    }

    @Override
    public Object cancelTwf(Trace t, Long id, String uuid) {
        T flow = dao().fetchByIdUuid(t, id, uuid);
        if (flow != null) {
            IActivity<?> bzActivity = bzActivity(flow);
            if (bzActivity != null) {
                return bzActivity.cancelTwf(t, flow.getTwfId(), flow.getTwfUuid());
            }
        }
        throw new BaseRuntimeException(Exceptions.CODE_ERROR_PARAMETER, "cancelTwf未实现，请在您的业务子类中实现此接口。");
    }

    @Override
    public void checkFlow(Trace t, FlowStep flow) {
        IActivity<?> bzActivity = bzActivity(flow);
        if (bzActivity != null) {
            bzActivity.checkFlow(t, flow);
        } else {
            super.checkFlow(t, flow);
        }
    }

    @Override
    public int complete(Trace t, Long twfInstId, String twfInstUuid, int op) {
        // return dao().complete(t, twfInstId, twfInstUuid, op);
        int rows = dao().complete(t, twfInstId, twfInstUuid, op);
        if (rows > 0) {
            List<T> flows = findByTwf(t, twfInstId, twfInstUuid);
            if (flows != null && !flows.isEmpty()) {
                for (T flow : flows) {
                    doConcreteCompleteBusiness(t, op, flow);
                }
            }
        }
        return rows;
    }

    /**
     * 完成业务对象更新
     * 
     * @param t
     * @param op
     *            Agree.Yes.getCode(),Agree.No.getCode()
     * @param flow
     */
    protected void doConcreteCompleteBusiness(Trace t, int op, T flow) {
        boolean completeThenDealBz = flow.isCompleteThenDealBz() == null || flow.isCompleteThenDealBz().equals(true);
        if (completeThenDealBz || (flow.getTwfId() != null && !Strings.isBlank(flow.getTwfUuid()))) {
            IActivity<?> bzActivity = bzActivity(flow);
            if (bzActivity != null) {
                bzActivity.doCompleteBusiness(t, op, flow);
            }
        }
    }

    protected abstract IActivity<?> bzActivity(FlowStep flow);

}
